# -*- coding: utf-8 -*-
"""
@Datetime: 2018/10/14
@Author: Zhang Yafei
"""


class Obj(object):
    """限制对象添加属性"""
    __slots__ = ['storage', 'stack_func', 'num', 'name']

    def __init__(self):
        """ 创建对象的时候若new返回一个对象会执行此方法 类名()"""
        object.__setattr__(self, 'storage', {})
        print('__init__')

    def __new__(cls, *args, **kwargs):
        """创建对象的时候会执行，返回一个对象
        应用：单例/rest framework序列化
        """
        print('__new__')
        return super(Obj, cls).__new__(cls, *args, **kwargs)

    def __call__(self):
        """ 对象()会执行 
        应用：flask源码请求入口，django请求入口(WSGIHandler.__call__)
        """
        print('__call__')

    def __hash__(self):
        """ hash()会执行 """
        return id(self)

    def __str__(self):
        """
        调用对象会执行此函数
        :return: string_obj 返回一个字符串对象
        """
        return '__str__'

    def __repr__(self):
        """
        转化为机器可以解释的语言
        case 1: repr(object)时会执行此函数
        case 2: 交互模式下打印对象会执行此函数
        :return: 用于对象信息的显示
        """
        return '__repr__'

    def __getattr__(self, item):
        """当访问不存在的属性时会调用"""
        return '__getattr__'

    def __setattr__(self, key, value):
        """给对象设置属性的时候会调用"""
        # self.key = value #容易出现循环调用
        print('__setattr__')
        if key == 'num':
            object.__setattr__(self, key, value - 100)
        else:
            object.__setattr__(self, key, value)

    def __delattr__(self, item):
        """删除属性的时候会调用"""
        print('__delattr__')
        object.__delattr__(self, item)

    def __getattribute__(self, item):
        """访问任何属性的时候都会调用此方法"""
        print('__getattribute__')
        return super(Obj, self).__getattribute__(item)

    def __del__(self):
        """对象的生命周期执行结束之后执行"""
        print('__del__')

    def __setitem__(self, key, value):
        """obj[key] = value时会调用此方法"""
        print('__setitem__')
        self.storage[key] = value

    def __getitem__(self, key):
        """obj[key]会调用此方法"""
        return self.storage.get(key, None)

    def __delitem__(self, key):
        """del obj[key]调用"""
        print('__delitem__')
        del self.storage[key]

    def __add__(self, other):
        return '__add__'

    def __sub__(self, other):
        return '__sub__'

    def __mul__(self, other):
        return '__mul'

    def __floordiv__(self, other):
        return '__floatdiv__'

    def __mod__(self, other):
        return '__mod__'

    def __divmod__(self, other):
        return '__divmod__'

    def __pow__(self, power, modulo=None):
        return '__pow__'


obj = Obj()  # __new__   __init__
print(obj)  # __str__
obj()  # __call__
print(Obj.__mro__)  # (<class '__main__.Obj'>, <class 'object'>)
obj.name = '__dict__'
print(obj.__dict__)
# print(Obj.__dict__)
print(repr(obj))  # __repr__
print(obj.world)  # __getattribute__    __getattr__
obj.num = 200  # __setattr__
print(obj.num)  # __getattribute__, 100
del obj.num  # __delattr__
print(obj.storage)  # {}
obj['name'] = '张亚飞'  # __setitem__
print(obj.storage)  # __getattrbute__  __getattrbute__   {'name':'张亚飞'}
print(obj['name'])  # __getattrbute__  张亚飞
del obj['name']  # __delitem__
print(obj['name'])  # __getitem__,  __getitem__, None
print(obj + 7)
print(obj - 1)
print(obj * 1)
print(obj // 1)
print(obj % 3)
print(obj.__divmod__(3))
print(obj.__pow__(2))

objx = Obj()
print(hash(obj))
print(hash(objx))
#  __del__

"""
这里我们想让__setattr__执行默认行为，也就是将value赋值给name，和object对象中的同样方法，做类似的操作。
但是这里我们不调用父类__setattr__的方法来实现，做这样的尝试得到的结果就是，超过循环调用深度，报错。因为
这里在执行初始化方法self.world = world的时候，就会调用__setattr__方法，而这里的__setattr__方法里面的
self.name = value又会调用自身。所以造成了循环调用。所以使用该魔法方法的时候要特别注意。
"""


class Friends(object):
    def __init__(self):
        self.name = 'zhang'
        self.age = 23

    def func(self):
        print('__func__')


class Xiaoming(Friends):
    score = 99

    def __init__(self):
        super(Xiaoming, self).__init__()
        self.run = 200


if __name__ == '__main__':
    # 一些内置数据类型没有__dict__属性
    ll = []
    dic = {}
    num = 3
    # print(ll.__dict__)     # AttributeError: 'list' object has no attribute '__dict__'
    # print(dic.__dict__)
    # print(num.__dict__)

    # 类的__dict__和对象的__dict__的区别
    f = Friends()  # 创建实例
    print(f.__dict__)
    f.message = 'hello world'
    f.func = lambda x:x
    print(f.__dict__)
    print(Friends.__dict__)

    # 继承关系的__dict__
    xiaoming = Xiaoming()
    print(xiaoming.__dict__)
    print(Xiaoming.__dict__)
"""
1. 一些内置数据类型没有__dict__
2. 实例的__dict__存有与实例相关的实例变量和函数.
类的__dict__则是和实例共享的变量,函数(方法,类属性).注意,类的__dict__并不包含其父类的属性.
3. 对象也有自己的__dict__属性， 存储self.xxx 信息，父子类对象公用__dict__
"""


class BAR(object):
    def __init__(self, cls):
        self.cls = cls


class NEW_OBJ(object):

    def __new__(cls, *args, **kwargs):
        # return super(NEW_OBJ, cls).__new__(cls, *args, **kwargs)   # <__main__.NEW_OBJ object at 0x000000D445061CF8>
        # return 123     # 123
        # return BAR          # <class '__main__.BAR'>
        # return BAR()        # <__main__.BAR object at 0x000000AD77141C50>
        return BAR(cls)       # <__main__.BAR object at 0x0000003BFFA31D68>


obj = NEW_OBJ()
print(obj)
"""new方法的返回值决定对象到底是什么"""


class Obj4():
    def __enter__(self):
        print('__enter__')

    def __exit__(self, exc_type, exc_val, exc_tb):
        print('__exit__')


with Obj4():
    print('执行中')

# __enter__
# 执行中
# __exit__
"""with 对象默认执行__enter__方法，执行结束执行__exit__方法"""


class Obj5(object):
    pass


setattr(Obj5,'send', lambda x:1)
obj5 = Obj5()
print(obj5.send())


""" 对象可以被for循环 """
class Obj(object):
    def __iter__(self):
        # return iter([1,2,3])
        yield 1
        yield 2
        yield 3


obj = Obj()

for item in obj:
    print(item)